package com.smh.yunpicturebackend.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.smh.yunpicturebackend.exception.BusinessException;
import com.smh.yunpicturebackend.exception.ErrorCode;
import com.smh.yunpicturebackend.mapper.PictureMapper;
import com.smh.yunpicturebackend.pojo.domain.Picture;
import com.smh.yunpicturebackend.pojo.domain.Space;
import com.smh.yunpicturebackend.pojo.domain.User;
import com.smh.yunpicturebackend.pojo.dto.space.analyze.*;
import com.smh.yunpicturebackend.pojo.vo.space.analyze.*;
import com.smh.yunpicturebackend.service.PictureService;
import com.smh.yunpicturebackend.service.SpaceAnalyzeService;
import com.smh.yunpicturebackend.service.SpaceService;
import com.smh.yunpicturebackend.service.UserService;
import com.smh.yunpicturebackend.utils.ThrowUtils;
import com.smh.yunpicturebackend.utils.UserThreadLocal;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author shiminghui
 * @date 2025/6/28 23:03
 * @description: 空间分析类
 */
@Service
public class SpaceAnalyzeServiceImpl implements SpaceAnalyzeService {
    @Resource
    private SpaceService spaceService;
    @Resource
    private PictureService pictureService;
    @Resource
    private UserService userService;
    @Resource
    private PictureMapper pictureMapper;

    private static SpaceUsageAnalyzeResponse getSpaceUsageAnalyzeResponse(List<Object> pictureObjList, long usedSize) {
        long usedCount = pictureObjList.size();
        // 封装返回结果
        SpaceUsageAnalyzeResponse spaceUsageAnalyzeResponse = new SpaceUsageAnalyzeResponse();
        spaceUsageAnalyzeResponse.setUsedSize(usedSize);
        spaceUsageAnalyzeResponse.setUsedCount(usedCount);
        // 公共图库无上限、无比例
        spaceUsageAnalyzeResponse.setMaxSize(null);
        spaceUsageAnalyzeResponse.setSizeUsageRatio(null);
        spaceUsageAnalyzeResponse.setMaxCount(null);
        spaceUsageAnalyzeResponse.setCountUsageRatio(null);
        return spaceUsageAnalyzeResponse;
    }

    /**
     * 填充查询条件
     *
     * @param spaceAnalyzeRequest 空间分析请求
     * @param queryWrapper        查询条件
     */
    private static void fillAnalyzeQueryWrapper(SpaceAnalyzeRequest spaceAnalyzeRequest, LambdaQueryWrapper<Picture> queryWrapper) {
        if (spaceAnalyzeRequest.isQueryAll()) {
            return;
        }
        if (spaceAnalyzeRequest.isQueryPublic()) {
            queryWrapper.isNull(Picture::getSpaceId);
            return;
        }
        Long spaceId = spaceAnalyzeRequest.getSpaceId();
        if (spaceId != null) {
            queryWrapper.eq(Picture::getSpaceId, spaceId);
            return;
        }
        throw new BusinessException(ErrorCode.PARAMS_ERROR, "未指定查询范围");
    }

    /**
     * 获取空间使用分析数据
     *
     * @param spaceUsageAnalyzeRequest SpaceUsageAnalyzeRequest 请求参数
     * @return SpaceUsageAnalyzeResponse 分析结果
     */
    @Override
    public SpaceUsageAnalyzeResponse getSpaceUsageAnalyze(SpaceUsageAnalyzeRequest spaceUsageAnalyzeRequest) {
        ThrowUtils.throwIf(spaceUsageAnalyzeRequest == null, ErrorCode.PARAMS_ERROR);
        if (spaceUsageAnalyzeRequest.isQueryAll() || spaceUsageAnalyzeRequest.isQueryPublic()) {
            // 查询全部或公共图库逻辑
            // 仅管理员可以访问
            boolean isAdmin = userService.isAdmin();
            ThrowUtils.throwIf(!isAdmin, ErrorCode.NO_AUTH_ERROR, "无权访问空间");
            // 统计公共图库的资源使用
            LambdaQueryWrapper<Picture> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.select(Picture::getPicSize);
            if (!spaceUsageAnalyzeRequest.isQueryAll()) {
                queryWrapper.isNull(Picture::getSpaceId);
            }
            List<Object> pictureObjList = pictureService.getBaseMapper().selectObjs(queryWrapper);
            long usedSize = pictureObjList.stream().mapToLong(result -> result instanceof Long ? (Long) result : 0).sum();
            return getSpaceUsageAnalyzeResponse(pictureObjList, usedSize);
        } else {
            // 查询指定空间
            Long spaceId = spaceUsageAnalyzeRequest.getSpaceId();
            ThrowUtils.throwIf(spaceId == null || spaceId <= 0, ErrorCode.PARAMS_ERROR);
            // 获取空间信息
            Space space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");

            // 权限校验：仅空间所有者或管理员可访问
            spaceService.checkSpaceAuth(space);

            // 构造返回结果
            SpaceUsageAnalyzeResponse response = new SpaceUsageAnalyzeResponse();
            response.setUsedSize(space.getTotalSize());
            response.setMaxSize(space.getMaxSize());
            // 后端直接算好百分比，这样前端可以直接展示
            double sizeUsageRatio = NumberUtil.round(space.getTotalSize() * 100.0 / space.getMaxSize(), 2).doubleValue();
            response.setSizeUsageRatio(sizeUsageRatio);
            response.setUsedCount(space.getTotalCount());
            response.setMaxCount(space.getMaxCount());
            double countUsageRatio = NumberUtil.round(space.getTotalCount() * 100.0 / space.getMaxCount(), 2).doubleValue();
            response.setCountUsageRatio(countUsageRatio);
            return response;
        }
    }

    /**
     * 获取空间分类使用情况
     *
     * @param spaceCategoryAnalyzeRequest 请求参数
     * @return 分类使用情况
     */
    @Override
    public List<SpaceCategoryAnalyzeResponse> getSpaceCategoryAnalyze(SpaceCategoryAnalyzeRequest spaceCategoryAnalyzeRequest) {
        ThrowUtils.throwIf(spaceCategoryAnalyzeRequest == null, ErrorCode.PARAMS_ERROR);

        // 检查权限
        checkSpaceAnalyzeAuth(spaceCategoryAnalyzeRequest);

        Long spaceId = spaceCategoryAnalyzeRequest.getSpaceId();
        boolean queryAll = spaceCategoryAnalyzeRequest.isQueryAll();

        // 保险操作
        if (spaceCategoryAnalyzeRequest.isQueryAll() || spaceCategoryAnalyzeRequest.isQueryPublic()) {
            spaceId = null;
        }

        // 使用 MyBatis-Plus 分组查询
        List<SpaceCategoryAnalyzeDto> spaceCategoryAnalyzeDtoList = pictureMapper.selectCountAndTotalSizeGroupByCategory(spaceId, queryAll);

        // 查询并转换结果
        return spaceCategoryAnalyzeDtoList
                .stream()
                .map(item -> {
                    String category = item.getCategory() != null ? item.getCategory() : "未分类";
                    Long count = item.getCount();
                    Long totalSize = item.getTotalSize();
                    return new SpaceCategoryAnalyzeResponse(category, count, totalSize);
                })
                .collect(Collectors.toList());
    }

    /**
     * 获取空间标签分析
     *
     * @param spaceTagAnalyzeRequest 请求参数
     * @return 标签分析结果
     */
    @Override
    public List<SpaceTagAnalyzeResponse> getSpaceTagAnalyze(SpaceTagAnalyzeRequest spaceTagAnalyzeRequest) {
        ThrowUtils.throwIf(spaceTagAnalyzeRequest == null, ErrorCode.PARAMS_ERROR);

        // 检查权限
        checkSpaceAnalyzeAuth(spaceTagAnalyzeRequest);

        // 构造查询条件
        LambdaQueryWrapper<Picture> queryWrapper = new LambdaQueryWrapper<>();
        fillAnalyzeQueryWrapper(spaceTagAnalyzeRequest, queryWrapper);

        // 查询所有符合条件的标签
        queryWrapper.select(Picture::getTags);

        List<String> tagsJsonList = pictureService.getBaseMapper().selectObjs(queryWrapper)
                .stream()
                .filter(ObjUtil::isNotNull)
                .map(Object::toString)
                .collect(Collectors.toList());

        // 合并所有标签并统计使用次数
        Map<String, Long> tagCountMap = tagsJsonList.stream()
                .flatMap(tagsJson -> JSONUtil.toList(tagsJson, String.class).stream())
                .collect(Collectors.groupingBy(tag -> tag, Collectors.counting()));

        // 转换为响应对象，按使用次数降序排序
        return tagCountMap.entrySet().stream()
                .sorted((e1, e2) -> Long.compare(e2.getValue(), e1.getValue())) // 降序排列
                .map(entry -> new SpaceTagAnalyzeResponse(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
    }

    /**
     * 根据图片大小进行分类分析
     *
     * @param spaceSizeAnalyzeRequest 请求参数
     * @return 响应对象
     */
    @Override
    public List<SpaceSizeAnalyzeResponse> getSpaceSizeAnalyze(SpaceSizeAnalyzeRequest spaceSizeAnalyzeRequest) {
        ThrowUtils.throwIf(spaceSizeAnalyzeRequest == null, ErrorCode.PARAMS_ERROR);

        // 检查权限
        checkSpaceAnalyzeAuth(spaceSizeAnalyzeRequest);

        // 构造查询条件
        LambdaQueryWrapper<Picture> queryWrapper = new LambdaQueryWrapper<>();
        fillAnalyzeQueryWrapper(spaceSizeAnalyzeRequest, queryWrapper);

        // 查询所有符合条件的图片大小
        queryWrapper.select(Picture::getPicSize);
        List<Long> picSizes = pictureService.getBaseMapper().selectObjs(queryWrapper)
                .stream()
                .map(size -> ((Number) size).longValue())
                .collect(Collectors.toList());

        // 定义分段范围，注意使用有序 Map
        final int _100KB = 100 * 1024;
        final int _500KB = 500 * 1024;
        final int _1MB = 1024 * 1024;

        Map<String, Long> sizeRanges = new LinkedHashMap<>();

        for (Long picSize : picSizes) {
            if (picSize <= _100KB) {
                sizeRanges.put("<100KB", sizeRanges.getOrDefault("<100KB", 0L) + 1);
            } else if (picSize <= _500KB) {
                sizeRanges.put("100KB-500KB", sizeRanges.getOrDefault("100KB-500KB", 0L) + 1);
            } else if (picSize <= _1MB) {
                sizeRanges.put("500KB-1MB", sizeRanges.getOrDefault("500KB-1MB", 0L) + 1);
            } else {
                sizeRanges.put(">1MB", sizeRanges.getOrDefault(">1MB", 0L) + 1);
            }
        }

        // 转换为响应对象
        return sizeRanges.entrySet().stream()
                .map(entry -> new SpaceSizeAnalyzeResponse(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
    }

    /**
     * 获取时间进行分析
     *
     * @param spaceUserAnalyzeRequest 请求参数
     * @return
     */
    @Override
    public List<SpaceUserAnalyzeResponse> getSpaceUserAnalyze(SpaceUserAnalyzeRequest spaceUserAnalyzeRequest) {
        ThrowUtils.throwIf(spaceUserAnalyzeRequest == null, ErrorCode.PARAMS_ERROR);
        // 检查权限
        checkSpaceAnalyzeAuth(spaceUserAnalyzeRequest);

        // 构造查询条件
        User user = UserThreadLocal.get();
        ThrowUtils.throwIf(user == null, ErrorCode.NOT_LOGIN_ERROR);

        String timeDimension = spaceUserAnalyzeRequest.getTimeDimension();
        Long spaceId = spaceUserAnalyzeRequest.getSpaceId();

        if (!Objects.equals(timeDimension, "day") && !Objects.equals(timeDimension, "month") && !Objects.equals(timeDimension, "week")) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "时间维度错误");
        }
        // 保险操作
        if (spaceUserAnalyzeRequest.isQueryAll() || spaceUserAnalyzeRequest.isQueryPublic()) {
            spaceId = null;
        }

        List<SpacePeriodAnalyzeDto> spacePeriodAnalyzeDtoList = pictureMapper.selectCountGroupByPeriod(user.getId(), spaceId, timeDimension, spaceUserAnalyzeRequest.isQueryAll());

        // 查询结果并转换
        return spacePeriodAnalyzeDtoList.stream()
                .map(item -> {
                    String period = item.getPeriod();
                    Long count = item.getCount();
                    return new SpaceUserAnalyzeResponse(period, count);
                })
                .collect(Collectors.toList());
    }

    /**
     * 用户空间使用排行
     *
     * @param spaceRankAnalyzeRequest
     * @return
     */
    @Override
    public List<Space> getSpaceRankAnalyze(SpaceRankAnalyzeRequest spaceRankAnalyzeRequest) {
        ThrowUtils.throwIf(spaceRankAnalyzeRequest == null, ErrorCode.PARAMS_ERROR);

        // 仅管理员可查看空间排行
        ThrowUtils.throwIf(!userService.isAdmin(), ErrorCode.NO_AUTH_ERROR, "无权查看空间排行");

        // 构造查询条件
        LambdaQueryWrapper<Space> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(Space::getId, Space::getSpaceName, Space::getUserId, Space::getTotalSize)
                .orderByDesc(Space::getTotalSize)
                .last("LIMIT " + spaceRankAnalyzeRequest.getTopN());// 取前 N 名

        // 查询结果
        return spaceService.list(queryWrapper);
    }

    /**
     * 检查空间分析权限
     *
     * @param spaceAnalyzeRequest 空间分析请求
     */
    private void checkSpaceAnalyzeAuth(SpaceAnalyzeRequest spaceAnalyzeRequest) {
        // 检查权限
        if (spaceAnalyzeRequest.isQueryAll() || spaceAnalyzeRequest.isQueryPublic()) {
            // 全空间分析或者公共图库权限校验：仅管理员可访问
            ThrowUtils.throwIf(!userService.isAdmin(), ErrorCode.NO_AUTH_ERROR, "无权访问公共图库");
        } else {
            // 私有空间权限校验
            Long spaceId = spaceAnalyzeRequest.getSpaceId();
            ThrowUtils.throwIf(spaceId == null || spaceId <= 0, ErrorCode.PARAMS_ERROR);
            Space space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
            spaceService.checkSpaceAuth(space);
        }
    }


}
